﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using TTMain.Net;
using TTMain.Core;
using TTMain.Settings;
using TTData.TTEventArgs;
using TTData;

namespace TTMain.UI
{
    #region Event Delegates
        
    public delegate void RoomUpdatedHandler(object sender, RoomUpdatesEventArgs e);
    public delegate void RefusedConnectionHandler(object sender);
    public delegate void JoinedTableAckHandler(object sender, Int32 roomId, List<String> playerList, List<Boolean> statesList);
    public delegate void JoinedTableNAckHandler(object sender);
    public delegate void UserJoinedTableHandler(object sender, TablePositionEventArgs e);
    public delegate void UserReadyHandler(object sender, NicknameEventArgs e);
    public delegate void UserCancelReadyHandler(object sender, NicknameEventArgs e);
    public delegate void UserTurnHandler(object sender, NicknameEventArgs e);
    public delegate void GameStartHandler(object sender, ListEventArgs e);
    public delegate void ChangeCardsHandler(object sender, ListEventArgs e);
    public delegate void ScoreHandler(object sender, NicknameEventArgs e);
    public delegate void ScoreHelpHandler(object sender, NicknameEventArgs e);
    public delegate void DiscardCardsHandler(object sender, ListEventArgs e);
    public delegate void DiscardPublicCardsHandler(object sender, NicknameEventArgs e);
    public delegate void PutHousesHandler(object sender, ListEventArgs e);
    public delegate void QuitHandler(object sender, NicknameEventArgs e);
    public delegate void DrawCardHandler(object sender, CardEventArgs e);
    public delegate void PutCardHandler(object sender, CardEventArgs e);
    public delegate void PlayersListHandler(object sender, List<String> e);
    public delegate void CreatedRoomAckHandler(object sender, Int32 roomId);
    public delegate void DisconnectHandler(object sender);
    public delegate void CreatedRoomNAckHandler(object sender);
    public delegate void SocketErrorHandler(object sender);
    public delegate void ServerDownErrorHandler(object sender);
    public delegate void TcpClientErrorHandler(object sender);



    #endregion
    
    /// <summary>
    /// 
    /// </summary>
    public class GameUI
    {
        #region Event Names
        
        public event RoomUpdatedHandler RoomUpdated;
        public event RefusedConnectionHandler RefusedConnection;
        public event JoinedTableAckHandler JoinedTableAck;
        public event JoinedTableNAckHandler JoinedTableNAck;
        public event UserJoinedTableHandler UserJoinedTable;
        public event UserReadyHandler UserReady;
        public event UserCancelReadyHandler UserCancelReady;
        public event UserTurnHandler UserTurn;
        public event ChangeCardsHandler ChangeCards;
        public event GameStartHandler GameStart;
        public event ScoreHandler Score;
        public event ScoreHelpHandler ScoreHelp;
        public event DiscardCardsHandler DiscardCards;
        public event DiscardPublicCardsHandler DiscardPublicCards;
        public event PutHousesHandler PutHouses;
        public event QuitHandler Quit;
        public event DrawCardHandler DrawCard;
        public event PutCardHandler PutCard;
        public event PlayersListHandler PlayersList;
        public event CreatedRoomAckHandler CreatedRoomAck;
        public event CreatedRoomNAckHandler CreatedRoomNAck;
        public event SocketErrorHandler SocketError;
        public event ServerDownErrorHandler ServerDownError;
        public event TcpClientErrorHandler TcpClientError;
        public event DisconnectHandler Disconnect;

        #endregion

        public GameNet _gameNet;
        private GameCore _gameCore;
        private GameSettings _gameSettings;
        private Int32 _roomId;

        /// <summary>
        /// Create a new GameUI object which loads the game settings from the setting file
        /// </summary>
        public GameUI()
        {
            _gameSettings = new GameSettings();
        }

        /// <summary>
        /// Gets the game settings
        /// </summary>
        /// <returns>the game settings</returns>
        public GameSettings GetGameSettings()
        {
            return _gameSettings;
        }

        #region Connection establishing methods

        /// <summary>
        /// Opens a socket for listening to updates from the server 
        /// </summary>
        /// <returns>whether or not the operation was successful or not </returns>
        public bool OpenLocalConnection()
        {               

            if (_gameNet == null)
            {
                _gameNet = new GameNet(this, _gameSettings.ServerIP, _gameSettings.ServerPort);
                bool ok = _gameNet.OpenConnection(_gameSettings.LocalPort);
                return ok;
            }
            else
            {
                if (_gameNet.IsConnected())
                    return false;
                else
                {
                    bool ok = _gameNet.OpenConnection(_gameSettings.LocalPort);
                    return ok;
                }
            }
        }

        /// <summary>
        /// Closes the listening socket and no more connections will be accepted
        /// </summary>
        public void CloseLocalConnection()
        {
            if (_gameNet != null)
                _gameNet.CloseConnection();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roomId"></param>
        public void SetRoomId(Int32 roomId)
        {
            _roomId = roomId;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="roomId"></param>
        public void QuitGame(Int32 roomId)
        {
            _gameNet.Send_Quit(_gameSettings.Nickname, roomId, 0);
        }

        #endregion

        #region Pre Game Started methods

        /// <summary>
        /// Sends a connection request to the server using the nickname as credentials
        /// </summary>
        public void ConnectToServer()
        {
            if ((_gameNet != null) && (_gameSettings != null))
                _gameNet.Send_Discover(_gameSettings.Nickname, _gameSettings.LocalPort);
        }

        /// <summary>
        /// Sends a request to the server for creating a new game room
        /// </summary>
        /// <param name="roomName">the name of the game room</param>
        public void CreateNewGameRoom(String roomName)
        {
            if ((_gameNet != null) && (_gameSettings != null))
                _gameNet.Send_CreateTable(_gameSettings.Nickname, roomName);
        }

        /// <summary>
        /// Sends a request to join a certain game room
        /// </summary>
        /// <param name="roomId">the id of the game room to join</param>
        public void JoinRoom(Int32 roomId)
        {
            if ((_gameNet != null) && (_gameSettings != null))
                _gameNet.Send_JoinTable(_gameSettings.Nickname, roomId);
        }

        public void SetState(Boolean ready, Int32 roomId)
        {
            if (_gameNet != null)
            {
                if (ready)
                    _gameNet.Send_StartGame(_gameSettings.Nickname, roomId);
                else
                    _gameNet.Send_CancelGame(_gameSettings.Nickname, roomId);
            }
        }

        #endregion        

        #region Game play methods

        public void GameStarted(Int32 noPlayers, List<Player> players, List<CityCard> initial6Cards)
        {
            _gameCore = new GameCore(noPlayers, players, initial6Cards);
        }

        public void StartTurn(String nickname)
        {
            _gameCore.StartTurn(nickname);
        }

        public ArrayList GetAvailableMoves(String nickname)
        {
            return _gameCore.GetAvailableMoves(nickname);
        }

        public CityCard GetDisplayCard(int position)
        {
            if ((position < 0) || (position > 5))
                return null;

            return _gameCore.GetDisplayCard(position);
        }

        public Int32 GetCardPutPosition(CityCard card) {
            if (_gameCore != null)
            {
                return _gameCore.GetCardPutPosition(_gameSettings.Nickname, card);
            }

            return Data.MoveConstants.POSITION_NONE;
        }

        public void UserPutCard(String nickname, String cardName, Int16 position)
        {
            if (_gameCore != null)
                _gameCore.PutCard(nickname, cardName, position);
        }

        public void UserDrawCard(String nickname, String cardName, Int32 position)
        {
            if (position == -1)                            
                _gameCore.TakeCardSupply(nickname, cardName);            
            else            
                _gameCore.TakeCardDisplay(nickname, position, cardName);
        }

        public void UserChangedCards(List<CityCard> cards)
        {
            _gameCore.UseAdministrator(cards);
        }

        public void UserPutHouses(String nickname, List<String> cityNames)
        {
            _gameCore.PutHouses(nickname, cityNames);
        }

        public void UserDiscardPublicCards(String nickname)
        {
            _gameCore.DiscardPublicCards(nickname);
        }

        public void UserDiscardPrivateCards(String nickname, List<String> cityNames)
        {
            _gameCore.DiscardPrivateCards(nickname, cityNames);
        }

        public void UserDiscardPrivateCards(String nickname)
        {
            _gameCore.DiscardPrivateCards(nickname);
        }


        
        #endregion

        public List<String> GetCitiesForHouses(String nickname)
        {
            if (_gameCore == null)
                return null;


            return _gameCore.GetCitiesForHouses(nickname);

        }

        public List<String> GetCitiesForHouses(String nickname, List<String> cityNames)
        {
            if (_gameCore == null)
                return null;


            return _gameCore.GetCitiesForHouses(nickname, cityNames);

        }

        public String GetPlayerColor(String nickname)
        {
            return _gameCore.GetPlayerColor(nickname);
        }

        #region UserEvent methods
        /// <summary>
        /// Notifies the game that the user drew a card
        /// </summary>
        /// <param name="position">0-6 value representing the position of the card. 0 for the back card</param>
        /// <returns>the next card</returns>
        public CityCard IDrawCard(Int32 position, Int32 roomId)
        {
            if (position == -1)
            {
                CityCard c = _gameCore.GetNextCityCard();
                _gameCore.TakeCardSupply(_gameSettings.Nickname, c);
                _gameNet.Send_DrawCards(_gameSettings.Nickname, roomId, position, c.CityName);
                return c;
            }
            else
            {
                CityCard c = _gameCore.GetNextCityCard();
                _gameCore.TakeCardDisplay(_gameSettings.Nickname, position, c);
                _gameNet.Send_DrawCards(_gameSettings.Nickname, roomId, position, c.CityName);
                return c;
            }
        }

        public void IPutCard(CityCard card, Int16 position, Int32 roomId)
        {
            if (_gameNet != null)
                _gameNet.Send_PutCard(_gameSettings.Nickname, roomId, position, card.CityName);
            if (_gameCore != null)
                _gameCore.PutCard(_gameSettings.Nickname, card, position);
        }

        /// <summary>
        /// Notifies the game that the user asked one of the 4 helpers for help
        /// </summary>
        /// <param name="helper">the type of the helper</param>
        public List<CityCard> IUseAdministrator(Int32 roomId)
        {
            if (_gameCore != null)
            {
                List<CityCard> list = _gameCore.GetAdministrator6Cards();
                _gameCore.UseAdministrator(list);
                ArrayList cardsName = new ArrayList();

                for (int i = 0 ; i< list.Count; i++) 
                    cardsName.Add(list[i].CityName);

                if (_gameNet != null)                
                    _gameNet.Send_ChangeCards(_gameSettings.Nickname, roomId, cardsName);
                
                return list;
            }

            return null;
        }

        /// <summary>
        /// Notifies the game that the user wants to score
        /// </summary>
        public void IScore()
        {            
            _gameNet.Send_Score(_gameSettings.Nickname, _roomId);
        }

        /// <summary>
        /// Notifies the game that the user wants to continues without scoring
        /// </summary>
        public void IContinue()
        {
        }

        public void IEndTurn(Int32 roomId)
        {
            if (_gameNet != null)
                _gameNet.Send_Continue(_gameSettings.Nickname, roomId);
        }

        public void IPutHouses(List<String> cityNames)
        {
            _gameNet.Send_PutHouses(_gameSettings.Nickname, _roomId, cityNames);            
            _gameCore.PutHouses(_gameSettings.Nickname, cityNames);
        }

        public void IDiscardPublicCards()
        {
            _gameCore.DiscardPublicCards(_gameSettings.Nickname);
            _gameNet.Send_DiscardPublicCards(_gameSettings.Nickname, _roomId);
        }

        public void IDiscardPrivateCards(List<CityCard> cards)
        {
            _gameCore.DiscardPrivateCards(_gameSettings.Nickname, cards);
            _gameNet.Send_DiscardCards(_gameSettings.Nickname, _roomId, cards);
        }

        public void IScoreHelp()
        {
            _gameNet.Send_ScoreHelp(_gameSettings.Nickname, _roomId);
        }

        #endregion

        #region Network updates methods

        public void Received_Offer(String nickname, ArrayList roomsList)
        {
            RoomUpdatesEventArgs args = new RoomUpdatesEventArgs(roomsList);
            OnRoomUpdated(args);
        }

        public void Received_Nack()
        {
            OnRefusedConnection();
        }

        public void Received_AckJoinTable(Int32 roomId, List<String> playersList, List<Boolean> statesList)
        {
            OnJoinedTableAck(roomId, playersList, statesList);
        }

        public void Received_NackJoinTable()
        {
            OnJoinedTableNAck();
        }

        public void Received_UserJoinTable(String nickname, Int32 playerPosition)
        {
            TablePositionEventArgs arg = new TablePositionEventArgs(nickname, playerPosition);
            OnUserJoinedTable(arg);
            
        }

        public void Received_UserStart(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnUserReady(arg);            
        }

        public void Received_UserCancel(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnUserCancelReady(arg);
        }

        public void Received_GameStart(String nickname, List<CityCard> cardNameList)
        {
            ListEventArgs arg = new ListEventArgs(nickname, cardNameList);
            OnGameStart(arg);
        }

        public void Received_UserTurn(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnUserTurn(arg);
        }

        public void Received_ChangeCards(String nickname, List<CityCard> cardNameList)
        {
            ListEventArgs arg = new ListEventArgs(nickname, cardNameList);
            OnChangeCards(arg);
        }

        public void Received_DrawCard(String nickname, Int32 position, String cardName)
        {
            CardEventArgs arg = new CardEventArgs(nickname, position, cardName);
            OnDrawCard(arg);
        }

        public void Received_PutCard(String nickname, Int32 position, String cardName)
        {
            CardEventArgs arg = new CardEventArgs(nickname, position, cardName);
            OnPutCard(arg);
        }

        public void Received_Score(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnScore(arg);
        }

        public void Received_ScoreHelp(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnScoreHelp(arg);
        }

        public void Received_DiscardCard(String nickname, List<String> cardNameList)
        {
            ListEventArgs arg = new ListEventArgs(nickname, cardNameList);            
            OnDiscardCards(arg);
        }

        public void Received_PutHouses(String nickname, List<String> cardNameList)
        {
            ListEventArgs arg = new ListEventArgs(nickname, cardNameList);
            OnPutHouses(arg);
        }

        public void Received_Quit(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnQuit(arg);
        }

        public void Received_NackCreateTable()
        {
            OnCreatedRoomNAck();

        }

        public void Received_AckCreateTable(Int32 roomId)
        {
            OnCreatedRoomAck(roomId);
        }

        public void Received_DiscardPublicCards(String nickname)
        {
            NicknameEventArgs arg = new NicknameEventArgs(nickname);
            OnDiscardPublicCards(arg);
        }

        public void Received_PlayersList(List<String> playerNames)
        {
            OnPlayersList(playerNames);
        }

        public void Received_Disconnect()
        {
            OnDisconnect();
        }


        #endregion

        #region Event methods

        protected virtual void OnRoomUpdated(RoomUpdatesEventArgs e)
        {
            if (RoomUpdated != null) RoomUpdated(this, e);
        }

        protected virtual void OnRefusedConnection()
        {
            if (RefusedConnection != null) RefusedConnection(this);
        }

        protected virtual void OnJoinedTableAck(Int32 roomId, List<String> playersList, List<Boolean> statesList)
        {
            if (JoinedTableAck != null) JoinedTableAck(this, roomId, playersList, statesList);
        }

        protected virtual void OnJoinedTableNAck()
        {
            if (JoinedTableNAck != null) JoinedTableNAck(this);
        }

        protected virtual void OnUserReady(NicknameEventArgs e)
        {
            if (UserReady != null) UserReady(this, e);
        }

        protected virtual void OnUserCancelReady(NicknameEventArgs e)
        {
            if (UserCancelReady != null) UserCancelReady(this, e);
        }

        protected virtual void OnUserJoinedTable(TablePositionEventArgs e)
        {
            if (UserJoinedTable != null) UserJoinedTable(this, e);
        }

        protected virtual void OnUserTurn(NicknameEventArgs e)
        {
            if (UserTurn != null) UserTurn(this, e);
        }

        protected virtual void OnGameStart(ListEventArgs e)
        {
            if (GameStart != null) GameStart(this, e);
        }

        protected virtual void OnChangeCards(ListEventArgs e)
        {
            if (ChangeCards != null) ChangeCards(this, e);
        }

        protected virtual void OnScore(NicknameEventArgs e)
        {
            if (Score != null) Score(this, e);
        }

        protected virtual void OnScoreHelp(NicknameEventArgs e)
        {
            if (ScoreHelp != null) ScoreHelp(this, e);
        }

        protected virtual void OnDiscardCards(ListEventArgs e)
        {
            if (DiscardCards != null) DiscardCards(this, e);
        }

        protected virtual void OnPutHouses(ListEventArgs e)
        {
            if (PutHouses != null) 
                PutHouses(this, e);
        }

        protected virtual void OnQuit(NicknameEventArgs e)
        {
            if (Quit != null) Quit(this, e);
        }

        protected virtual void OnDrawCard(CardEventArgs e)
        {
            if (DrawCard != null) DrawCard(this, e);
        }

        protected virtual void OnPutCard(CardEventArgs e)
        {
            if (PutCard != null) PutCard(this, e);
        }

        protected virtual void OnCreatedRoomAck(Int32 roomId)
        {
            if (CreatedRoomAck != null) CreatedRoomAck(this, roomId);
        }

        protected virtual void OnCreatedRoomNAck()
        {
            if (CreatedRoomNAck != null) CreatedRoomNAck(this);
        }

        protected virtual void OnDiscardPublicCards(NicknameEventArgs e)
        {
            if (DiscardPublicCards != null) DiscardPublicCards(this, e);
        }

        protected virtual void OnPlayersList(List<String> e)
        {
            if (PlayersList != null) PlayersList(this, e);
        }

        protected virtual void OnServerDownError()
        {
            if (ServerDownError != null) ServerDownError(this);
        }

        protected virtual void OnTcpClientError()
        {
            if (TcpClientError != null) TcpClientError(this);
        }

        protected virtual void OnSocketError()
        {
            if (SocketError != null) SocketError(this);
        }

        protected virtual void OnDisconnect()
        {
            if (Disconnect != null) Disconnect(this);
        }

        #endregion

        #region Error Handling methods 

        public void HandleSocketError()
        {
            OnSocketError();
        }

        public void HandleTcpClientError()
        {
        }

        public void HandleServerDownError()
        {
            OnServerDownError();
        }

        #endregion

        #region Bonuses

        public BonusCard CalculateBonusRoadLength(String nickname)
        {
            return _gameCore.GetRoadLengthBonus(nickname);
        }

        public CarrigeCard CalculateCarrigeCard(String nickname, Boolean isHelper)
        {
            if (!isHelper)
                return _gameCore.GetCarrigeCard(nickname);
            else
                return _gameCore.GetCarrigeCardWithHelp(nickname);
        }

        public BonusCard CalculateBonusAllRegion(String nickname)
        {
            return _gameCore.GetAllRegionsBonus(nickname);
        }

        public BonusCard CalculateBonusRegion(String nickname, Int32 bonusRegionType)
        {
            return _gameCore.GetRegionBonus(nickname, bonusRegionType);
        }

        public BonusCard CalculateEndGame(String nickname)
        {
            return _gameCore.GetEndBonus(nickname);
        }

        public BonusCard GetCurrentBonus(Int32 bonusType)
        {
            return _gameCore.GetCurrentBonusCard(bonusType);            
        }

        public CarrigeCard GetCurrentCarrigeCard(Int32 value)
        {
            return _gameCore.GetCurrentCarrigeCard(value);
        }
        
        #endregion

        public List<Player> GetPlayers()
        {
            return _gameCore.GetPlayerList();
        }

    }
}
